package server;

import config.Context;
import config.Host;
import config.Mapper;
import config.Wrapper;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;

/**
 * Minicat主类
 */
public class Bootstrap4 {

    Mapper mapper = new Mapper();

    private int port = 8080;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    /**
     * 程序开始
     */
    public void start() throws IOException {
        // 加载并解析server.xml配置文件
        loadServerXml();

        // 定义线程池
        int corePoolSize = 10;
        int maximumPoolSize = 100;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );

        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("========>>>Minicat start on port:" + 8080);

        System.out.println("===========>>>使用线程池改造");
        /**
         * 使用线程池改造
         */
        while (true) {
            Socket socket = serverSocket.accept();
            ServletProcessor4 servletProcessor = new ServletProcessor4(socket, mapper.getHostList());
            threadPoolExecutor.execute(servletProcessor);
        }
    }

    // 加载server.xml文件
    private void loadServerXml() {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            // 读取成文档
            Document document = saxReader.read(resourceAsStream);
            // 获取根元素
            Element rootElement = document.getRootElement();
            // 获取service元素
            List<Element> serviceNodes = rootElement.selectNodes("//Service");
            for (Element serviceNode : serviceNodes) {
                // 获取Connector元素
                List<Element> connectorNodes = serviceNode.selectNodes("//Connector");
                for (Element connectorNode : connectorNodes) {
                    // 获取Engine元素
                    Element engineNode = (Element) connectorNode.selectSingleNode("Engine");
                    // 获取host元素
                    List<Element> hostNodes = engineNode.selectNodes("//Host");
                    for (Element hostNode : hostNodes) {
                        String name = hostNode.attributeValue("name");
                        String appBase = hostNode.attributeValue("appBase");

                        // 加载项目
                        List<Context> contexts = loadContext(appBase);

                        // 添加host
                        mapper.addHost(new Host(name, contexts));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 加载class文件夹下的类
     */
    private List<Context> loadContext(String path) {
        List<Context> contexts = new ArrayList<>();
        try {
            // webapps的子文件夹就是项目工程
            File[] files = new File(path).listFiles(new FileFilter() {
                @Override
                public boolean accept(File file) {
                    return (file.isDirectory());
                }
            });

            // 每个文件夹代表一个项目
            for (File file : files) {
                Map<String, String> servletMap = new HashMap<>();

                // 1、加载web.xml
                String webXmlPath = file.getPath() + "/web.xml";
                parseWebXml(webXmlPath, servletMap);

                // 2、加载servlet
                String classPath = file.getPath() + "/";
                List<Wrapper> wrappers = loadServlet(classPath, servletMap);

                // 添加项目
                contexts.add(new Context(file.getName(), wrappers));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return contexts;
    }

    /**
     * 加载配置文件：web.xml
     */
    private void parseWebXml(String path, Map<String, String> servletMap) {
        try {
            // 解析web.xml文件
            SAXReader saxReader = new SAXReader();
            // 读取成文档
            Document document = saxReader.read(new File(path));
            // 获取根元素
            Element rootElement = document.getRootElement();
            // 获取servlet元素
            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (Element selectNode : selectNodes) {
                // <servlet-name>
                Element servletNameElement = (Element) selectNode.selectSingleNode("servlet-name");
                // <servlet-class>
                Element servletClassElement = (Element) selectNode.selectSingleNode("servlet-class");

                String servletName = servletNameElement.getStringValue();
                String servletClass = servletClassElement.getStringValue();

                // 获取匹配的url-pattern
                Element servletMappingElement = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                Element urlPatternElement = (Element) servletMappingElement.selectSingleNode("url-pattern");
                String urlPattern = urlPatternElement.getStringValue();

                // 将urlPattern和servletClass关联
                servletMap.put(urlPattern, servletClass);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 加载servlet class
    private List<Wrapper> loadServlet(String path, Map<String, String> servletMap) throws Exception {

        List<Wrapper> wrappers = new ArrayList<>();

        URL url = new URL("file:" + path);
        // 类加载器去加载class信息
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
        // 加载该项目中的servlet class
        for (Map.Entry<?, ?> entry : servletMap.entrySet()) {
            // 全限定类名
            String servletName = entry.getValue().toString();
            // 对应的请求路径
            String servletPath = entry.getKey().toString();

            // 将类加载到JVM中
            Class<?> servletClass = urlClassLoader.loadClass(servletName);
            // 实例化
            Servlet servlet = (Servlet) servletClass.newInstance();
            // 添加servlet
            wrappers.add(new Wrapper(servletPath, servlet));
        }
        urlClassLoader.close();

        return wrappers;
    }


    /**
     * Minicat启动入口
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap4 bootstrap = new Bootstrap4();
        try {
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
